package com.wande.dataplatform.filecollection.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wande.common.core.exception.ServiceException;
import com.wande.common.core.utils.MapstructUtils;
import com.wande.common.core.utils.StringUtils;
import com.wande.common.mybatis.core.page.PageQuery;
import com.wande.common.mybatis.core.page.TableDataInfo;
import com.wande.dataplatform.filecollection.common.constant.FileCollectionConstants;
import com.wande.dataplatform.filecollection.domain.CollectionRule;
import com.wande.dataplatform.filecollection.domain.CollectionTask;
import com.wande.dataplatform.filecollection.domain.FileRecord;
import com.wande.dataplatform.filecollection.domain.bo.CollectionRuleBo;
import com.wande.dataplatform.filecollection.domain.bo.CollectionTaskBo;
import com.wande.dataplatform.filecollection.domain.vo.CollectionRuleVo;
import com.wande.dataplatform.filecollection.domain.vo.CollectionTaskVo;
import com.wande.dataplatform.filecollection.domain.vo.FileRecordVo;
import com.wande.dataplatform.filecollection.mapper.CollectionRuleMapper;
import com.wande.dataplatform.filecollection.mapper.CollectionTaskMapper;
import com.wande.dataplatform.filecollection.mapper.FileRecordMapper;
import com.wande.dataplatform.filecollection.service.IFileCollectionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 文件采集服务实现
 *
 * @author wande
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileCollectionServiceImpl implements IFileCollectionService {

    private final CollectionRuleMapper collectionRuleMapper;
    private final CollectionTaskMapper collectionTaskMapper;
    private final FileRecordMapper fileRecordMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createRule(CollectionRuleBo bo) {
        // 检查规则编码是否重复
        LambdaQueryWrapper<CollectionRule> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CollectionRule::getRuleCode, bo.getRuleCode());
        if (collectionRuleMapper.exists(wrapper)) {
            throw new ServiceException("规则编码已存在");
        }

        CollectionRule rule = MapstructUtils.convert(bo, CollectionRule.class);
        rule.setStatus(FileCollectionConstants.RuleStatus.DISABLED);
        collectionRuleMapper.insert(rule);

        log.info("创建采集规则成功, ruleId={}, ruleCode={}", rule.getId(), rule.getRuleCode());
        return rule.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRule(CollectionRuleBo bo) {
        CollectionRule rule = collectionRuleMapper.selectById(bo.getId());
        if (rule == null) {
            throw new ServiceException("采集规则不存在");
        }

        // 如果规则编码变更，检查是否重复
        if (!rule.getRuleCode().equals(bo.getRuleCode())) {
            LambdaQueryWrapper<CollectionRule> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(CollectionRule::getRuleCode, bo.getRuleCode());
            wrapper.ne(CollectionRule::getId, bo.getId());
            if (collectionRuleMapper.exists(wrapper)) {
                throw new ServiceException("规则编码已存在");
            }
        }

        CollectionRule updateRule = MapstructUtils.convert(bo, CollectionRule.class);
        collectionRuleMapper.updateById(updateRule);

        // 如果规则已启用，需要同步更新DolphinScheduler任务
        if (FileCollectionConstants.RuleStatus.ENABLED.equals(rule.getStatus()) && rule.getDsTaskId() != null) {
            // TODO: 调用DolphinScheduler API更新任务
            log.info("需要同步更新DolphinScheduler任务, dsTaskId={}", rule.getDsTaskId());
        }

        log.info("更新采集规则成功, ruleId={}", bo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRule(Long id) {
        CollectionRule rule = collectionRuleMapper.selectById(id);
        if (rule == null) {
            throw new ServiceException("采集规则不存在");
        }

        if (FileCollectionConstants.RuleStatus.ENABLED.equals(rule.getStatus())) {
            throw new ServiceException("请先禁用规则后再删除");
        }

        // 删除DolphinScheduler任务
        if (rule.getDsTaskId() != null) {
            // TODO: 调用DolphinScheduler API删除任务
            log.info("需要删除DolphinScheduler任务, dsTaskId={}", rule.getDsTaskId());
        }

        collectionRuleMapper.deleteById(id);
        log.info("删除采集规则成功, ruleId={}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enableRule(Long id) {
        CollectionRule rule = collectionRuleMapper.selectById(id);
        if (rule == null) {
            throw new ServiceException("采集规则不存在");
        }

        if (FileCollectionConstants.RuleStatus.ENABLED.equals(rule.getStatus())) {
            throw new ServiceException("规则已启用");
        }

        // 验证规则配置
        validateRule(rule);

        // 创建或更新DolphinScheduler任务
        if (rule.getDsTaskId() == null) {
            // TODO: 调用DolphinScheduler API创建任务
            Long dsTaskId = createDolphinSchedulerTask(rule);
            rule.setDsTaskId(dsTaskId);
            log.info("创建DolphinScheduler任务成功, dsTaskId={}", dsTaskId);
        } else {
            // TODO: 调用DolphinScheduler API启动任务
            log.info("启动DolphinScheduler任务, dsTaskId={}", rule.getDsTaskId());
        }

        rule.setStatus(FileCollectionConstants.RuleStatus.ENABLED);
        collectionRuleMapper.updateById(rule);

        log.info("启用采集规则成功, ruleId={}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disableRule(Long id) {
        CollectionRule rule = collectionRuleMapper.selectById(id);
        if (rule == null) {
            throw new ServiceException("采集规则不存在");
        }

        if (FileCollectionConstants.RuleStatus.DISABLED.equals(rule.getStatus())) {
            throw new ServiceException("规则已禁用");
        }

        // 暂停DolphinScheduler任务
        if (rule.getDsTaskId() != null) {
            // TODO: 调用DolphinScheduler API暂停任务
            log.info("暂停DolphinScheduler任务, dsTaskId={}", rule.getDsTaskId());
        }

        rule.setStatus(FileCollectionConstants.RuleStatus.DISABLED);
        collectionRuleMapper.updateById(rule);

        log.info("禁用采集规则成功, ruleId={}", id);
    }

    @Override
    public CollectionRuleVo getRule(Long id) {
        return collectionRuleMapper.selectVoById(id);
    }

    @Override
    public TableDataInfo<CollectionRuleVo> listRules(CollectionRuleBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<CollectionRule> wrapper = buildRuleQueryWrapper(bo);
        Page<CollectionRuleVo> page = collectionRuleMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long triggerTask(Long ruleId) {
        CollectionRule rule = collectionRuleMapper.selectById(ruleId);
        if (rule == null) {
            throw new ServiceException("采集规则不存在");
        }

        // 创建采集任务
        CollectionTask task = new CollectionTask();
        task.setRuleId(ruleId);
        task.setTaskCode(IdUtil.fastSimpleUUID());
        task.setStatus(FileCollectionConstants.TaskStatus.PENDING);
        task.setStartTime(LocalDateTime.now());
        task.setFileCount(0);
        task.setTotalRecords(0L);
        task.setSuccessRecords(0L);
        task.setFailedRecords(0L);
        collectionTaskMapper.insert(task);

        // TODO: 异步执行采集任务
        log.info("手动触发采集任务, taskId={}, ruleId={}", task.getId(), ruleId);

        return task.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void stopTask(Long taskId) {
        CollectionTask task = collectionTaskMapper.selectById(taskId);
        if (task == null) {
            throw new ServiceException("采集任务不存在");
        }

        if (!FileCollectionConstants.TaskStatus.RUNNING.equals(task.getStatus())) {
            throw new ServiceException("任务未在运行中");
        }

        // TODO: 停止任务执行
        task.setStatus(FileCollectionConstants.TaskStatus.FAILED);
        task.setEndTime(LocalDateTime.now());
        task.setErrorMessage("任务被手动停止");
        collectionTaskMapper.updateById(task);

        log.info("停止采集任务成功, taskId={}", taskId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long retryTask(Long taskId) {
        CollectionTask oldTask = collectionTaskMapper.selectById(taskId);
        if (oldTask == null) {
            throw new ServiceException("采集任务不存在");
        }

        // 创建新任务
        return triggerTask(oldTask.getRuleId());
    }

    @Override
    public CollectionTaskVo getTask(Long taskId) {
        return collectionTaskMapper.selectVoById(taskId);
    }

    @Override
    public TableDataInfo<CollectionTaskVo> listTasks(CollectionTaskBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<CollectionTask> wrapper = buildTaskQueryWrapper(bo);
        Page<CollectionTaskVo> page = collectionTaskMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<FileRecordVo> listFileRecords(CollectionTaskBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<FileRecord> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(bo.getId() != null, FileRecord::getTaskId, bo.getId());
        wrapper.orderByDesc(FileRecord::getCreateTime);
        Page<FileRecordVo> page = fileRecordMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    public FileRecordVo getFileRecord(Long id) {
        return fileRecordMapper.selectVoById(id);
    }

    @Override
    public String downloadFile(Long id) {
        FileRecord fileRecord = fileRecordMapper.selectById(id);
        if (fileRecord == null) {
            throw new ServiceException("文件记录不存在");
        }

        if (StringUtils.isEmpty(fileRecord.getOssPath())) {
            throw new ServiceException("文件未上传到对象存储");
        }

        // TODO: 生成MinIO预签名URL
        log.info("生成文件下载URL, fileId={}, ossPath={}", id, fileRecord.getOssPath());
        return fileRecord.getOssPath();
    }

    /**
     * 构建规则查询条件
     */
    private LambdaQueryWrapper<CollectionRule> buildRuleQueryWrapper(CollectionRuleBo bo) {
        LambdaQueryWrapper<CollectionRule> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotEmpty(bo.getRuleName()), CollectionRule::getRuleName, bo.getRuleName());
        wrapper.eq(StringUtils.isNotEmpty(bo.getRuleCode()), CollectionRule::getRuleCode, bo.getRuleCode());
        wrapper.eq(StringUtils.isNotEmpty(bo.getFileType()), CollectionRule::getFileType, bo.getFileType());
        wrapper.eq(StringUtils.isNotEmpty(bo.getSourceType()), CollectionRule::getSourceType, bo.getSourceType());
        wrapper.eq(StringUtils.isNotEmpty(bo.getStatus()), CollectionRule::getStatus, bo.getStatus());
        wrapper.orderByDesc(CollectionRule::getCreateTime);
        return wrapper;
    }

    /**
     * 构建任务查询条件
     */
    private LambdaQueryWrapper<CollectionTask> buildTaskQueryWrapper(CollectionTaskBo bo) {
        LambdaQueryWrapper<CollectionTask> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(bo.getRuleId() != null, CollectionTask::getRuleId, bo.getRuleId());
        wrapper.eq(StringUtils.isNotEmpty(bo.getTaskCode()), CollectionTask::getTaskCode, bo.getTaskCode());
        wrapper.eq(StringUtils.isNotEmpty(bo.getStatus()), CollectionTask::getStatus, bo.getStatus());
        wrapper.orderByDesc(CollectionTask::getCreateTime);
        return wrapper;
    }

    /**
     * 验证规则配置
     */
    private void validateRule(CollectionRule rule) {
        if (StringUtils.isEmpty(rule.getSourceConfig())) {
            throw new ServiceException("来源配置不能为空");
        }

        if (FileCollectionConstants.ScheduleType.MANUAL.equals(rule.getScheduleType())) {
            return;
        }

        if (StringUtils.isEmpty(rule.getScheduleConfig())) {
            throw new ServiceException("调度配置不能为空");
        }

        // TODO: 验证Cron表达式
    }

    /**
     * 创建DolphinScheduler任务
     */
    private Long createDolphinSchedulerTask(CollectionRule rule) {
        // TODO: 调用DolphinScheduler API创建任务
        // 这里返回模拟的任务ID
        return System.currentTimeMillis();
    }

    @Override
    public java.util.Map<String, Object> getTaskStatistics(Long ruleId) {
        java.util.Map<String, Object> statistics = new java.util.HashMap<>();
        
        LambdaQueryWrapper<CollectionTask> wrapper = Wrappers.lambdaQuery();
        if (ruleId != null) {
            wrapper.eq(CollectionTask::getRuleId, ruleId);
        }
        
        // 总任务数
        Long totalTasks = collectionTaskMapper.selectCount(wrapper);
        statistics.put("totalTasks", totalTasks);
        
        // 成功任务数
        LambdaQueryWrapper<CollectionTask> successWrapper = Wrappers.lambdaQuery();
        if (ruleId != null) {
            successWrapper.eq(CollectionTask::getRuleId, ruleId);
        }
        successWrapper.eq(CollectionTask::getStatus, FileCollectionConstants.TaskStatus.SUCCESS);
        Long successTasks = collectionTaskMapper.selectCount(successWrapper);
        statistics.put("successTasks", successTasks);
        
        // 失败任务数
        LambdaQueryWrapper<CollectionTask> failedWrapper = Wrappers.lambdaQuery();
        if (ruleId != null) {
            failedWrapper.eq(CollectionTask::getRuleId, ruleId);
        }
        failedWrapper.eq(CollectionTask::getStatus, FileCollectionConstants.TaskStatus.FAILED);
        Long failedTasks = collectionTaskMapper.selectCount(failedWrapper);
        statistics.put("failedTasks", failedTasks);
        
        // 运行中任务数
        LambdaQueryWrapper<CollectionTask> runningWrapper = Wrappers.lambdaQuery();
        if (ruleId != null) {
            runningWrapper.eq(CollectionTask::getRuleId, ruleId);
        }
        runningWrapper.eq(CollectionTask::getStatus, FileCollectionConstants.TaskStatus.RUNNING);
        Long runningTasks = collectionTaskMapper.selectCount(runningWrapper);
        statistics.put("runningTasks", runningTasks);
        
        // 成功率
        double successRate = totalTasks > 0 ? (double) successTasks / totalTasks * 100 : 0;
        statistics.put("successRate", String.format("%.2f", successRate));
        
        return statistics;
    }

    @Override
    public java.util.List<java.util.Map<String, Object>> getTaskTrend(Long ruleId, Integer days) {
        java.util.List<java.util.Map<String, Object>> trend = new java.util.ArrayList<>();
        
        LocalDateTime endDate = LocalDateTime.now();
        LocalDateTime startDate = endDate.minusDays(days);
        
        for (int i = 0; i < days; i++) {
            LocalDateTime date = startDate.plusDays(i);
            LocalDateTime nextDate = date.plusDays(1);
            
            java.util.Map<String, Object> dayData = new java.util.HashMap<>();
            dayData.put("date", date.toLocalDate().toString());
            
            // 查询当天的任务统计
            LambdaQueryWrapper<CollectionTask> wrapper = Wrappers.lambdaQuery();
            if (ruleId != null) {
                wrapper.eq(CollectionTask::getRuleId, ruleId);
            }
            wrapper.ge(CollectionTask::getCreateTime, date);
            wrapper.lt(CollectionTask::getCreateTime, nextDate);
            
            Long totalTasks = collectionTaskMapper.selectCount(wrapper);
            dayData.put("totalTasks", totalTasks);
            
            // 成功任务数
            LambdaQueryWrapper<CollectionTask> successWrapper = Wrappers.lambdaQuery();
            if (ruleId != null) {
                successWrapper.eq(CollectionTask::getRuleId, ruleId);
            }
            successWrapper.ge(CollectionTask::getCreateTime, date);
            successWrapper.lt(CollectionTask::getCreateTime, nextDate);
            successWrapper.eq(CollectionTask::getStatus, FileCollectionConstants.TaskStatus.SUCCESS);
            Long successTasks = collectionTaskMapper.selectCount(successWrapper);
            dayData.put("successTasks", successTasks);
            
            // 失败任务数
            LambdaQueryWrapper<CollectionTask> failedWrapper = Wrappers.lambdaQuery();
            if (ruleId != null) {
                failedWrapper.eq(CollectionTask::getRuleId, ruleId);
            }
            failedWrapper.ge(CollectionTask::getCreateTime, date);
            failedWrapper.lt(CollectionTask::getCreateTime, nextDate);
            failedWrapper.eq(CollectionTask::getStatus, FileCollectionConstants.TaskStatus.FAILED);
            Long failedTasks = collectionTaskMapper.selectCount(failedWrapper);
            dayData.put("failedTasks", failedTasks);
            
            trend.add(dayData);
        }
        
        return trend;
    }
}
